package com.sf.osms.dep.processor.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class FTPTool {
	
	private static Logger logger = LoggerFactory.getLogger(FTPTool.class);
	
	private static String encoding = System.getProperty("file.encoding");
	
	private FTPClient ftpClient; 
	private FTPConnectInfo connectInfo;
	
	public FTPTool(FTPConnectInfo connectInfo){
		this.connectInfo = connectInfo;
	}
	
	/**
	 * 下载文件夹：结束此方法后需要进行logout
	 * @param remotePath
	 * @param localPath
	 */
	public void downloadDiretory(String remotePath,String localPath) throws Exception{
	
		try {
			if(this.getConnect()){
				int reply;
				ftpClient.enterLocalPassiveMode();
				// 设置文件传输类型为二进制  
	            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);  
	            // 获取ftp登录应答代码  
	            reply = ftpClient.getReplyCode();  
	            // 验证是否登陆成功  
	            if (!FTPReply.isPositiveCompletion(reply)) {  
	                ftpClient.disconnect();  
	                System.err.println("FTP server refused connection.");  
	            }  
	            
	            // 转移到FTP服务器目录至指定的目录下  
	            ftpClient.changeWorkingDirectory(new String(remotePath.getBytes(encoding),"iso-8859-1"));  
	            // 获取文件列表  
	            FTPFile[] fs = ftpClient.listFiles();
	            FileUtil.createDirIfNot(localPath);
	            for (FTPFile ff : fs) { 
	               //若是目录
	               if(ff.isDirectory()){
	            	   downloadDiretory(remotePath+"/"+ff.getName(), localPath+"/"+ff.getName());
	               }else{
	            	   
	        		   File localFile = new File(localPath + "/" + ff.getName());  
	                   OutputStream is = new FileOutputStream(localFile);  
	                   ftpClient.retrieveFile(ff.getName(), is);  
	                   is.close();
	            	  
	               }
	              
	            }
	           
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("move diretory fail!");
		}
	}
	
	/**
	 * 将remotePath下面的文件全部下载
	 * @param remotePath
	 * @param localPath
	 * @param remoteBackupPath 当为null的时候，不进行备份操作
	 * @return
	 * @throws Exception
	 */
	public List<String> downloadFiles(String remotePath,String localPath,String remoteBackupPath) throws Exception{
		
		if(StringUtils.isEmpty(remotePath) || StringUtils.isEmpty(localPath)){
			return null;
		}
		
		List<String> result = new ArrayList<String>();
		try {
			if(this.getConnect()){
				int reply;
				ftpClient.enterLocalPassiveMode();
				// 设置文件传输类型为二进制  
	            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);  
	            // 获取ftp登录应答代码  
	            reply = ftpClient.getReplyCode();  
	            // 验证是否登陆成功  
	            if (!FTPReply.isPositiveCompletion(reply)) {  
	                ftpClient.disconnect();  
	                logger.error("******ftp客户端没有登录成功！******");  
	                return result;  
	            }  
	            
	            // 转移到FTP服务器目录至指定的目录下  
	           boolean changeStatus =   ftpClient.changeWorkingDirectory(new String(remotePath.getBytes(encoding),"iso-8859-1"));  
	           if(!changeStatus) {
	        	   logger.error("********{} 目录不存在，无法下载文件*********",remotePath);
	        	   return result;
	           }
	           // 获取文件列表  
	            FTPFile[] fs = ftpClient.listFiles();
	            if(null == fs || fs.length == 0){
	            	return null;
	            }
	            
	        	logger.info("******FPT下载开始******");
	            for (FTPFile ff : fs) {  
	            	
	            	//进行文件的筛选
	                if(ff.isDirectory()){
	                	continue;
	                }
	                
	                //文件的前缀,多个前缀由,分开   这里的逗号为英文格式
	                String filePrefix = connectInfo.getFilePrefix();
	                if(!StringUtils.isBlank(filePrefix)){
	                	String[] prefixs = filePrefix.split(",");
	 	                boolean isContain = false;
	 	                for (String prefix : prefixs) {
	 						if(ff.getName().startsWith(prefix) || ff.getName().startsWith(prefix.toUpperCase())){
	 							isContain = true;
	 							break;
	 						}
	 					}
		                if(!isContain){
		                	continue;
		                }
	                }
	                
	                //文件的后缀,多个后缀由,分开  这里的逗号为英文格式
	                String fileSuffix = connectInfo.getFileSuffix();
	                if(!StringUtils.isBlank(fileSuffix)){
	                	String[] suffixs = fileSuffix.split(",");
	 	                boolean isContain = false;
	 	                for (String suffix : suffixs) {
	 						if(ff.getName().endsWith(suffix) || ff.getName().endsWith(suffix.toUpperCase())){
	 							isContain = true;
	 							break;
	 						}
	 					}
		                if(!isContain){
		                	continue;
		                }
	                }
	              	           
	                //文件的下载
	                String dateStr = DateUtil.dateFomat(new Date(), "yyyyMMddHHmmss"); //时间戳备份
	                File localFile = FileUtil.createFile(localPath + File.separator + dateStr + "-" +ff.getName());
	                OutputStream is = null;
                    try {
                    	is = new FileOutputStream(localFile);  
                        ftpClient.retrieveFile(new String(ff.getName().getBytes(),"iso-8859-1"), is);  
					} catch (Exception e) {
						logger.error("******FPT下载文件失败："+remotePath + File.separator + ff.getName()+"******");
						throw e;
					}finally{
						if(null != is){
							is.close();
						}
						
					}
                    logger.info("******FPT下载文件成功："+remotePath + File.separator + ff.getName()+"******");
                    
                    //进行文件的备份
                    if(StringUtils.isNotEmpty(remoteBackupPath) && localFile.length() != 0){
        	           
                        boolean isBackup = moveFile(remotePath + "/" +ff.getName(), remoteBackupPath+ "/" + dateStr + "-" +ff.getName());
                        if(!isBackup){
                        	logger.error("******FPT备份文件失败："+remotePath + "/" + ff.getName()+"******");
                        }
                    }
                   
                    
                    result.add(localPath + File.separator + dateStr + "-" +ff.getName());
	               
	            }  
	  
	            ftpClient.logout();   
				
			}
		} catch (Exception e) {
			logger.error("******FPT下载异常："+remotePath + "/******"+e);
			throw e;
			
		}finally{
			 if (ftpClient.isConnected()) {  
	                try {  
	                    ftpClient.disconnect();  
	                } catch (IOException ioe) {
	                	ioe.printStackTrace();
	                }  
	         }
			
		}
		
		return result;
	}

	/**
	 * 下载指定ftp服务器上目录下面的文件
	 * @param remotePath
	 * @param remoteFileName
	 * @param localPath
	 * @return
	 */
	public boolean downloadFile(String remotePath,String remoteFileName,String localPath){
		boolean result = false;
		
		try {
			if(this.getConnect()){
				int reply;
				ftpClient.enterLocalPassiveMode();
				// 设置文件传输类型为二进制  
	            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);  
	            // 获取ftp登录应答代码  
	            reply = ftpClient.getReplyCode();  
	            // 验证是否登陆成功  
	            if (!FTPReply.isPositiveCompletion(reply)) {  
	                ftpClient.disconnect();  
	                System.err.println("FTP server refused connection.");  
	                return result;  
	            }  
	            
	            // 转移到FTP服务器目录至指定的目录下  
	            ftpClient.changeWorkingDirectory(new String(remotePath.getBytes(encoding),"iso-8859-1"));  
	            // 获取文件列表  
	            FTPFile[] fs = ftpClient.listFiles();
	            FileUtil.createDirIfNot(localPath);
	            for (FTPFile ff : fs) {  
	                if (ff.getName().equals(remoteFileName)) {  
	                    File localFile = new File(localPath + File.separator + ff.getName()); 
	                    OutputStream is = null;
	                    try {
	                    	 is = new FileOutputStream(localFile);  
	 	                    ftpClient.retrieveFile(remotePath + File.separator + ff.getName(), is);
						} catch (Exception e) {
							throw new Exception("IO Exception");
						}finally{
							if(null != is){
								 is.close();  
							}
						}
	                     
	                   
	                }  
	            }  
	  
	            ftpClient.logout();  
	            result = true; 
				
			}
		} catch (Exception e) {
			result = false; 
			
		}finally{
			 if (ftpClient.isConnected()) {  
	                try {  
	                    ftpClient.disconnect();  
	                } catch (IOException ioe) {
	                	ioe.printStackTrace();
	                }  
	            }  
		}
		
		return result;
	}

	/**
	 * 上传文件
	 * 
	 * @param filename
	 * @param input
	 * @return
	 * @throws IOException
	 */
	public boolean uploadFile(String localFilePath,String remotePath) throws IOException {
		boolean success = false;
		File file = new File(localFilePath);
		if (file.exists() && file.isFile()) {
			InputStream input = null;
			try {
				input = new FileInputStream(file);
				// 判断是否已连接到服务器
				if (this.getConnect()) {
					boolean result = false;
					// 转移工作目录至指定目录下
					boolean change = ftpClient.changeWorkingDirectory(remotePath);
					ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
					if (change) {
						result = ftpClient.storeFile(new String(file.getName()
								.getBytes(encoding), "iso-8859-1"), input);
						if (result) {
							logger.info("上传成功!");
						}
					}
					ftpClient.logout();
					success = true;
				}
			} catch (IOException e) {
				logger.error("上传文件失败", e);
				success = false;
			} finally {
				this.close();
				if (null != input) {
					input.close();
				}
			}
		}

		return success;
	}

	/**
	 * 根据文件名称删除文件
	 * 
	 * @param fileNames
	 * @return List<String> 删除成功的文件列表
	 */
	public List<String> deleteRemoteFile(String deletePath,List<String> fileNames) {
		List<String> deletedFileList= new ArrayList<String>();
        if(!CollectionUtil.isEmpty(fileNames) && StringUtils.isNoneEmpty(deletePath)){
			// 判断是否已连接到服务器
			if (this.getConnect()) {
				try {
					// 转移到FTP服务器目录
					ftpClient.changeWorkingDirectory(deletePath);
					for (String fileName : fileNames) {
						String filePath =  deletePath + "/" + fileName;
						FTPFile[] fs =ftpClient.listFiles(filePath);
						if(fs.length == 1){
							boolean success = ftpClient.deleteFile(filePath);
							if(success){
								deletedFileList.add(fileName);
							}else{
								logger.info("FTP delete file fail!"+filePath);
							}
						}else{
							deletedFileList.add(fileName);
							logger.info("Remove from not exist FTP  file from toBedeletedFileList.txt : "+filePath);
						}
					}
					ftpClient.logout();
				} catch (IOException e) {
					logger.error("删除文件失败", e);
				} finally {
					this.close();
				}
			}
        }
        
        return deletedFileList;
	}

	/**
	 * connect ftpserver 
	 * @return if success return true,unless false
	 */
	private boolean connect() {
		// 是否已连接
		if (ftpClient != null && ftpClient.isConnected()) {
			return true;
		}
		boolean iFlag = false;
		ftpClient = new FTPClient();
		int cnt =1;
		do{
			try {
				    ftpClient.setConnectTimeout(100*1000);
				    ftpClient.setDefaultTimeout(100*1000);
				    ftpClient.setDataTimeout(100*1000);
					ftpClient.connect(connectInfo.getUrl(), connectInfo.getPort());
					// 登录
					ftpClient.login(connectInfo.getUserName(), connectInfo.getPassword());
		
					ftpClient.setControlEncoding(encoding);
					// 检验是否连接成功
					int reply = ftpClient.getReplyCode();
					if (!FTPReply.isPositiveCompletion(reply)) {
						this.close();
						iFlag = false;
						logger.info("Connect FTP server fail.");
					} else {
						iFlag = true;
						logger.info("Connect FTP server success.");
					}
				
			} catch (Exception e) {
				logger.info("FTP连接失败,次数:"+cnt);
				logger.error("连接FTP服务器失败"+connectInfo.getUrl()+":"+connectInfo.getPort(), e);
			}
		}while( !iFlag && cnt++ < 2);
		
		return iFlag;
	}
	
	/**
	 * judge whether connected
	 * 
	 * @return
	 */
	private boolean getConnect() {
		// 是否已连接
		boolean iFlag = true;
		if (null == ftpClient || !ftpClient.isConnected()) {
			iFlag = this.connect();
		}
		return iFlag;
	}

	/**
	 * close connect
	 */
	public void close() {
		try {
			if (null != ftpClient && ftpClient.isConnected()) {
				ftpClient.disconnect();
			}
		} catch (IOException ex) {
			logger.error("关闭FTP服务器连接失败", ex);
		}
	}
	
	public void logout(){
		try {
			ftpClient.logout();
		} catch (IOException e) {
			e.printStackTrace();
			logger.error("关闭FTP服务器连接失败", e);
		}
	}
	/**
	 * 将ftp服务器上的文件进行移动，后面需要进行logout
	 * @param remoteOldFile 文件的全路径名称
	 * @param remoteNewFile 移动到指定文件中的全路径
	 * @return
	 */
	public boolean moveFile(String remoteOldFile,String remoteNewFile){
		boolean result = false;
		try {
			if(this.getConnect()){
				int reply;
				ftpClient.enterLocalPassiveMode();
				// 设置文件传输类型为二进制  
	            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);  
	            // 获取ftp登录应答代码  
	            reply = ftpClient.getReplyCode();  
	            // 验证是否登陆成功  
	            if (!FTPReply.isPositiveCompletion(reply)) {  
	                ftpClient.disconnect();  
	                System.err.println("FTP server refused connection.");  
	                return result;  
	            }  
	            
	            result = ftpClient.rename(new String(remoteOldFile.getBytes(),"iso-8859-1"), new String(remoteNewFile.getBytes(encoding),"iso-8859-1"));
				
			}
		} catch (Exception e) {
			logger.error(ExceptionUtils.getExceptionStackString(e));
			result = false; 
		}
		return result;
	}
	
	public static void main(String[] args) throws Exception{
		String url = "202.66.140.166";
		int port = 21;
		String userName = "jpAdmin";
		String password = "Seibu!0514";
		FTPConnectInfo fInfo = new FTPConnectInfo(url, port, userName, password,"","");
		FTPTool fTool = new FTPTool(fInfo);
		fTool.downloadFile("/DEP_DATA/SG/HNC_HAN", "test.csv", "E:");
		//fTool.moveFile("/test_build/backup/test1.csv", "/test/test.csv");
		//fTool.downloadDiretory("/test", "E:/test");
		//fTool.close();
		
	}
}
